﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Security;

using mvcForum.Core.Interfaces.Services;

using SimpleLocalisation;

namespace mvcForum.Web.Services {

	public class MembershipService : IMembershipService {
		private TextManager text;

		public MembershipService(TextManager text) {
			this.text = text;
		}

		public Boolean CreateAccount(String accountName, String password, String emailAddress, out String errorMessage) {
			errorMessage = String.Empty;

			if (String.IsNullOrWhiteSpace(accountName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
			if (String.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
			if (String.IsNullOrWhiteSpace(emailAddress)) throw new ArgumentException("Value cannot be null or empty.", "email");

			MembershipCreateStatus status;
			Membership.CreateUser(accountName, password, emailAddress, null, null, true, null, out status);
			if (status != MembershipCreateStatus.Success) {
				errorMessage = this.ErrorCodeToString(status, text);
			}

			return status == MembershipCreateStatus.Success;
		}

		public void UnlockAccount(String accountName) {
			Membership.Provider.UnlockUser(accountName);
		}

		private IAccount GetAccountInstance(MembershipUser user) {
			return new Account {
				AccountName = user.UserName,
				CreationDate = user.CreationDate,
				EmailAddress = user.Email,
				IsApproved = user.IsApproved,
				IsLockedOut = user.IsLockedOut,
				LastActivityDate = user.LastActivityDate,
				ProviderUserKey = user.ProviderUserKey,
				LastLockoutDate = user.LastLockoutDate,
				LastLoginDate = user.LastLoginDate
			};
		}

		private MembershipUser GetMUInstance(IAccount account) {
			return new MembershipUser(Membership.Provider.Name, account.AccountName, account.ProviderUserKey, account.EmailAddress, null, null, account.IsApproved, account.IsLockedOut, account.CreationDate, account.LastLoginDate, account.LastActivityDate, DateTime.MinValue, account.LastLockoutDate);
		}

		public String GetAccountNameByEmailAddress(String emailAddress) {
			return Membership.GetUserNameByEmail(emailAddress);
		}

		public IAccount GetAccount(Boolean online) {
			return this.GetAccountInstance(Membership.GetUser(online));
		}

		public IAccount GetAccount(Object id) {
			return this.GetAccountInstance(Membership.GetUser(id));
		}

		public IAccount GetAccountByName(String accountName) {
			return this.GetAccountInstance(Membership.GetUser(accountName, false));
		}

		public IAccount GetAccountByName(String accountName, Boolean online) {
			return this.GetAccountInstance(Membership.GetUser(accountName, online));
		}

		public IAccount GetAccountByEmailAddress(String emailAddress) {
			return this.GetAccountInstance(Membership.GetUser(Membership.GetUserNameByEmail(emailAddress), false));
		}

		public void UpdateAccount(IAccount account) {
			Membership.UpdateUser(this.GetMUInstance(account));
		}

		public void DeleteAccount(String accountName) {
			this.DeleteAccount(accountName, true);
		}

		public void DeleteAccount(String accountName, Boolean deleteAllRelatedData) {
			Membership.DeleteUser(accountName, deleteAllRelatedData);
		}

		public IEnumerable<IAccount> GetAllAccounts(Int32 pageIndex, Int32 pageSize, out Int32 records) {
			List<IAccount> accounts = new List<IAccount>();
			foreach (MembershipUser user in Membership.GetAllUsers(pageIndex, pageSize, out records)) {
				accounts.Add(this.GetAccountInstance(user));
			}

			return accounts;
		}

		public void CreateRole(String roleName) {
			Roles.CreateRole(roleName);
		}

		public String[] GetRolesForAccount(String accountName) {
			return Roles.GetRolesForUser(accountName);
		}

		//public String[] GetRolesForAccount() {
		//    return Roles.GetRolesForUser();
		//}

		public String[] GetAllRoles() {
			return Roles.GetAllRoles();
		}

		public Boolean IsAccountInRole(String accountName, String roleName) {
			return Roles.IsUserInRole(accountName, roleName);
		}

		public void RemoveAccountFromRoles(String accountName, String[] roles) {
			Roles.RemoveUserFromRoles(accountName, roles);
		}

		public void AddAccountToRoles(String accountName, String[] roles) {
			Roles.AddUserToRoles(accountName, roles);
		}

		public Boolean ValidateAccount(String accountName, String password) {
			return Membership.ValidateUser(accountName, password);
		}

		private String ErrorCodeToString(MembershipCreateStatus createStatus, TextManager texts) {
			// See http://go.microsoft.com/fwlink/?LinkID=177550 for a full list of status codes.
			switch (createStatus) {
				case MembershipCreateStatus.DuplicateUserName:
				case MembershipCreateStatus.DuplicateEmail:
				case MembershipCreateStatus.InvalidPassword:
				case MembershipCreateStatus.InvalidEmail:
				case MembershipCreateStatus.InvalidAnswer:
				case MembershipCreateStatus.InvalidQuestion:
				case MembershipCreateStatus.InvalidUserName:
				case MembershipCreateStatus.ProviderError:
				case MembershipCreateStatus.UserRejected:
					return texts.Get(createStatus.ToString(), ns: "mvcForum.WebUI.MembershipErrors");
				default:
					return texts.Get("Default", ns: "mvcForum.WebUI.MembershipErrors");
			}
		}

		public String ResetPassword(IAccount account) {
			MembershipUser user = this.GetMUInstance(account);
			return user.ResetPassword();
		}

		public Boolean ChangePassword(IAccount account, String oldPassword, String newPassword) {
			MembershipUser user = this.GetMUInstance(account);
			return user.ChangePassword(oldPassword, newPassword);
		}
	}
}